/* 
 * Shuriken is the legal property of its developers. Please refer to the
 * COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections; 
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Shuriken.Core.Ranking;

namespace Shuriken.Core.Store
{
    public class StoreManager
    {
        private static StoreManager m_ourselves;
        private List<IStore> m_storeList;
        private QNStore m_SubjectStore; 

        /// <summary>
        /// Defualt constructor
        /// </summary>
        public StoreManager()
        {            
            m_storeList = new List<IStore>();

            m_SubjectStore = new QNStore("System", "Internal Commands", true, new Scanners.VoidScanner());
            m_storeList.Add(m_SubjectStore);
        }

        /// <summary>
        /// Gets the default instance of the StoreManager
        /// </summary>
        /// <returns></returns>
        public static StoreManager GetDefaultInstance()
        {
            if (m_ourselves == null)
            {
                m_ourselves = new StoreManager();

                // Needs to call Initialize after the constructor finished. 
                m_ourselves.Initialize();
            }

            return m_ourselves; 
        }

        /// <summary>
        /// Ends the initial setup of the class 
        /// </summary>
        /// <remarks>
        /// Completes the initial setup of the class. This method needs to be separated from the constructor, otherwise the static constructor would be called many times. 
        /// </remarks>
        private void Initialize()
        {
            m_storeList.Add(new StartMenuStore());
            m_storeList.Add(new FavoritesStore());
            m_storeList.Add(new ControlPanelStore());

            // m_storeList.Add(new QNStore("Custom", "Utils Folder", true, new Scanners.FileSystemScanner(new string[] {"c:\\utils"}, 20, new string[] {"*.exe"})));
            // m_storeList.Add(new QNStore("Custom", "Utils Folder", true, new Scanners.FileSystemScanner(new string[] {"C:\\Users\\kgyuris\\utils"}, 20, new string[] {"*.exe"})));
            
            UpdateStores();

            //m_storeList.Add(StartMenuStore.GetInstance());
            //m_storeList.Add(ControlPanelStore.GetInstance());  // <- this call is to force the link store to parse through the start menu.
            //m_storeList.Add(FavoritesStore.GetInstance());

            RegistrationManager.GetDefaultInstance().LoadModules();
        }

        private void UpdateStores()
        {
            foreach (QNStore store in m_storeList)
            {
                store.UpdateStore();
            }
        }

        /// <summary>
        /// List of stores managed. 
        /// </summary>
        public List<IStore> StoreList
        {
            get
            {
                return m_storeList; 
            }
        }

        /// <summary>
        /// Launches the item 
        /// </summary>
        /// <param name="item">item to launch</param>
        //public void LaunchItem(IStoreItem item)
        //{
        //    item.ExecuteDefaultAction();
        //}

        /// <summary>
        /// Searching the store based on the searchTerm
        /// </summary>
        /// <param name="resultList">Items matching the search will be returned in this list</param>
        /// <param name="searchTerm">search term to use</param>
        internal void UpdateListWithSearchTerm(ref SortedDisplayItemList resultList, string searchTerm)
        {

            if (searchTerm == null)
            {
                return;
            }

            if (searchTerm.Equals(string.Empty))
            {
                return;
            }

            if (resultList.Count == 0)
            {
                SortedDisplayItemList result = new SortedDisplayItemList(); 
                foreach (IStore store in m_storeList)
                {
                    if (!store.StoreEnabled)
                    {
                        continue;
                    }

                    foreach (ISearchable s in store.Values)
                    {
                        result.Add(s);
                    }
                }

                resultList = SearchWithinList(result, searchTerm);
            }
            else
            {
                SortedDisplayItemList result; 
                result = SearchWithinList(resultList, searchTerm);

                resultList = result;               
            }

            resultList.SortDisplayItemList();
            resultList.Reverse();
        }

        /// <summary>
        /// Searches for items within the list. 
        /// </summary>
        /// <param name="resultList">List to search in</param>
        /// <param name="searchTerm">Search Term</param>
        /// <returns>Result of the search</returns>
        private SortedDisplayItemList SearchWithinList(SortedDisplayItemList resultList, string searchTerm)
        {
            double rank;
            MutableIndexSet hitMask; 

            SortedDisplayItemList result = new SortedDisplayItemList();
            Ranking.IRankProvider rankProvider = Shuriken.Core.Ranking.RankingService.DefaultInstance;

            foreach (ISearchable item in resultList)
            {
                hitMask = new MutableIndexSet();
                rank = rankProvider.CalculateRank(item, searchTerm, hitMask);

                if (rank == 0) continue; // continue if it does not fit 

                item.Rank = rank;
                item.HitMask = hitMask;
                item.SearchTerm = searchTerm;
                result.Add(item);
            }

            return result; 
        }

        internal void AddSubject(QNStoreItem qnStoreItem)
        {
            System.Diagnostics.Trace.Assert(qnStoreItem != null, "Null subject has been passed!");
            //qnStoreItem
            m_SubjectStore.AddStoreItem(qnStoreItem);
        }
    }
}
